package com.mbc.common.manager;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.mbc.common.CommonConstants;
import com.mbc.common.dao.CommonDAOFactory;
import com.mbc.common.dao.BranchChangeLogDAO;
import com.mbc.common.dao.UserDAO;
import com.mbc.common.dao.UserInBranchesDAO;
import com.mbc.common.dao.UserInRolesDAO;
import com.mbc.common.data.BranchChangeLogDataList;
import com.mbc.common.data.UserDataList;
import com.mbc.common.entities.BranchChangeLog;
import com.mbc.common.entities.User;
import com.mbc.common.entities.UserInOffices;
import com.mbc.common.entities.UserInRoles;
import com.mbc.common.exception.DataDuplicationException;
import com.mbc.common.exception.DataNotFoundException;
import com.mbc.common.exception.UnauthorizedAccessException;
import com.mbc.common.param.CriteriaParams;
import com.mbc.common.utils.KeyGenerator;

public class UserMgr extends AbstractMgr {
	
	private UserDAO userDAO;
	
	public static final byte USER_ONLINE = 2;
	
	public UserMgr()
	{}
	
	public UserMgr(String sessionId)
	{
		this.sessionId = sessionId;
	}
	
	public void resetPassword(long userId, String oldPassword, String newPassword)throws Exception{
		openConnection();
		try {
			userDAO = CommonDAOFactory.getUserDAO(getConnection());
			User l_User = userDAO.find(userId);
			if(l_User.getPassword().equals(oldPassword)){
				userDAO.resetPassword(userId, newPassword);
			}
			else
				throw new UnauthorizedAccessException("Password does not match.");
		} catch (Exception e) {
			throw e;
		} finally{
			closeConnection();
		}
	}
	
	public void createUser(User user, String createdBy) throws Exception
	{
		openConnection();
		try {
			dbManager.beginTransaction();
			
			user.setUserId(KeyGenerator.generateKey(getConnection()));
			
			userDAO = CommonDAOFactory.getUserDAO(getConnection());
			UserInRolesDAO l_UserInRolesDAO = CommonDAOFactory.getUserInRolesDAO(getConnection());
			UserInBranchesDAO l_UserInOfficesDAO = CommonDAOFactory.getUserInBranchesDAO(getConnection());
			
			userDAO.create(user);
			
			for (UserInOffices l_UserInOffices : user.getUserInOfficeList()) {
				l_UserInOffices.setUserId(user.getUserId());
				l_UserInOfficesDAO.create(l_UserInOffices);
			}
			
			if(user.getUserInOfficeList().size() > 0){
				BranchChangeLog l_log = new BranchChangeLog();
				l_log.setLoginId(user.getLoginId());
				l_log.setBranchId(user.getUserInOfficeList().get(0).getOfficeId());
				l_log.setChangedBy(createdBy);
				l_log.setChangedDate(new Date());
				
				BranchChangeLogDAO l_logDAO = CommonDAOFactory.getBranchChangeLogDAO(getConnection());
				l_logDAO.create(l_log);
			}
			
			for (UserInRoles l_UserInRoles : user.getUserInRolesList()) {
				l_UserInRoles.setUserId(user.getUserId());
				l_UserInRolesDAO.create(l_UserInRoles);
			}
			
			commintTransaction();
		} catch (SQLException e) {
			rollbackTransaction();
			if(DataDuplicationException.UNIQUE_KEY_ERROR_CODE == e.getErrorCode())
				throw new DataDuplicationException(e.getMessage());
			else
				throw e;
		}
		finally
		{
			closeConnection();
		}
	}
	
	public void updateUser(User user, String updatedBy)throws Exception
	{
		openConnection();
		try {
			dbManager.beginTransaction();
			userDAO = CommonDAOFactory.getUserDAO(getConnection());
			UserInRolesDAO l_UserInRolesDAO = CommonDAOFactory.getUserInRolesDAO(getConnection());
			UserInBranchesDAO l_UserInBranchesDAO = CommonDAOFactory.getUserInBranchesDAO(getConnection());
			
			ArrayList<UserInOffices> l_userInOfficeList = l_UserInBranchesDAO.findByUserId(user.getUserId());
			if(l_userInOfficeList.size() > 0){
				if(l_userInOfficeList.get(0).getOfficeId() != user.getUserInOfficeList().get(0).getOfficeId()){
					BranchChangeLogDAO l_logDAO = CommonDAOFactory.getBranchChangeLogDAO(getConnection());
					BranchChangeLog l_log = new BranchChangeLog();
				}
			}
			
			userDAO.update(user);
			l_UserInRolesDAO.deleteByUserId(user.getUserId());
			l_UserInBranchesDAO.deleteByUserId(user.getUserId());
			
			for (UserInOffices l_UserInOffices : user.getUserInOfficeList()) {
				l_UserInOffices.setUserId(user.getUserId());
				l_UserInBranchesDAO.create(l_UserInOffices);
			}
			
			for (UserInRoles l_UserInRoles : user.getUserInRolesList()) {
				l_UserInRoles.setUserId(user.getUserId());
				l_UserInRolesDAO.create(l_UserInRoles);
			}
			commintTransaction();
		} catch (Exception e) {
			rollbackTransaction();
			throw e;
		}
		finally{
			closeConnection();
		}
	}
	
	public void changeUserBranch(String loginId, long branchId, String updatedBy)throws Exception{
		openConnection();
		try {
			beginTransaction();
			userDAO = CommonDAOFactory.getUserDAO(getConnection());
			User l_user = userDAO.findByLoginId(loginId);
			if(l_user == null)
				throw new DataNotFoundException("Login ID (" + loginId + ") is not found.");
			UserInBranchesDAO l_userInBranchesDAO = CommonDAOFactory.getUserInBranchesDAO(getConnection());
			List<UserInOffices> l_userInBranchList = l_userInBranchesDAO.findByUserId(l_user.getUserId());
			
			BranchChangeLogDAO l_logDAO = CommonDAOFactory.getBranchChangeLogDAO(getConnection());
			if(l_userInBranchList.size() > 0){
				if(branchId != l_userInBranchList.get(0).getOfficeId()){
					l_userInBranchesDAO.deleteByUserId(l_user.getUserId());
					UserInOffices l_userInOffice = new UserInOffices();
					l_userInOffice.setUserId(l_user.getUserId());
					l_userInOffice.setOfficeId(branchId);
					l_userInBranchesDAO.create(l_userInOffice);
					
					BranchChangeLog l_log = new BranchChangeLog();
					l_log.setLoginId(loginId);
					l_log.setBranchId(branchId);
					l_log.setChangedBy(updatedBy);
					l_log.setChangedDate(new Date());
					l_logDAO.create(l_log);
				}
			} else {
				l_userInBranchesDAO.deleteByUserId(l_user.getUserId());
				UserInOffices l_userInOffice = new UserInOffices();
				l_userInOffice.setUserId(l_user.getUserId());
				l_userInOffice.setOfficeId(branchId);
				l_userInBranchesDAO.create(l_userInOffice);
				
				BranchChangeLog l_log = new BranchChangeLog();
				l_log.setLoginId(loginId);
				l_log.setBranchId(branchId);
				l_log.setChangedBy(updatedBy);
				l_log.setChangedDate(new Date());
				l_logDAO.create(l_log);
			}
			commintTransaction();
		} catch (Exception e) {
			rollbackTransaction();
			throw e;
		} finally {
			closeConnection();
		}
	}
	
	public void deleteUser(long userId)throws Exception{
		openConnection();
		try {
			userDAO = CommonDAOFactory.getUserDAO(getConnection());
			userDAO.delete(userId);			
		} catch (Exception e) {
			rollbackTransaction();
		}
		finally{
			closeConnection();
		}
	}
	
	public UserDataList getUserList(CriteriaParams cri)throws Exception{
		openConnection();
		try {
			userDAO = CommonDAOFactory.getUserDAO(getConnection());
			return userDAO.getList(cri);
		} catch (Exception e) {
			throw e;
		}
		finally{
			closeConnection();
		}
	}
	
	public User getUser(long userId) throws Exception{
		openConnection();
		try {
			userDAO = CommonDAOFactory.getUserDAO(getConnection());
			User l_User = userDAO.find(userId);
			if(l_User != null)
			{
				UserInRolesDAO l_UserInRolesDAO = CommonDAOFactory.getUserInRolesDAO(getConnection());
				UserInBranchesDAO l_UserInOfficeDAO = CommonDAOFactory.getUserInBranchesDAO(getConnection());
				
				l_User.setUserInRolesList(l_UserInRolesDAO.findByUserId(userId));
				l_User.setUserInOfficeList(l_UserInOfficeDAO.findByUserId(userId));
			}
			return l_User;
		} catch (Exception e) {
			throw e;
		} finally {
			closeConnection();
		}
	}
	
	public User getUser(String loginId)throws Exception{
		openConnection();
		try {
			userDAO = CommonDAOFactory.getUserDAO(getConnection());
			User l_User = userDAO.findByLoginId(loginId);
			if(l_User != null)
			{
				UserInRolesDAO l_UserInRolesDAO = CommonDAOFactory.getUserInRolesDAO(getConnection());
				UserInBranchesDAO l_UserInOfficeDAO = CommonDAOFactory.getUserInBranchesDAO(getConnection());
				
				l_User.setUserInRolesList(l_UserInRolesDAO.findByUserId(l_User.getUserId()));
				l_User.setUserInOfficeList(l_UserInOfficeDAO.findByUserId(l_User.getUserId()));
			}
			return l_User;
		} catch (Exception e) {
			throw e;
		} finally {
			closeConnection();
		}
	}
	
	public void updateUserOnlineStatus(long userId, boolean isOnline)throws Exception{
		openConnection();
		try {
			userDAO = CommonDAOFactory.getUserDAO(getConnection());
			if(isOnline)
				userDAO.updateUserOnlineStatus(userId, USER_ONLINE);
			else
				userDAO.updateUserOnlineStatus(userId, CommonConstants.RecordStatus.active);
		} catch (Exception e) {
			throw e;
		} finally {
			closeConnection();
		}
	}
	
	public BranchChangeLogDataList getBranchChangeLog(CriteriaParams cri)throws Exception{
		openConnection();
		try {
			userDAO = CommonDAOFactory.getUserDAO(getConnection());
			if(userDAO.findByLoginId(cri.getKeyword()) == null)
				throw new DataNotFoundException("Login ID (" + cri.getKeyword() + ") is not found.");
			BranchChangeLogDAO l_logDAO = CommonDAOFactory.getBranchChangeLogDAO(getConnection());
			return l_logDAO.getLogs(cri);
		} catch (Exception e) {
			throw e;
		} finally {
			closeConnection();
		}
	}
}
